/**
 @ClassName:expression
 @Author:TwT
 @Date:2022/5/20 23:58
 @Version:1.0
 **/
const OP_REG = /^\w+$/
const OPERATOR_REG = /^\+|\-|\*|\/$/
const descOpr = {
    '(': 0,
    '+': 1,
    '-': 1,
    '*': 2,
    '/': 2,
    ')': 3,
}


/**
 * 中缀表达式 转 前缀表达式
 * @param midExpre 如：(1+(3*4)/6)-5
 */
function getPrefixExpression(midExpre) {
    let varStack = []
    let oprStack = []
    // (1+(3*4)/6)-5
    for (let i = 0; i < midExpre.length; i++) {
        const cur = midExpre[i];
        if (OP_REG.test(cur)) {
            varStack.push(cur)
        } else if ("(" === cur) {
            oprStack.push(cur)
        } else if (")" === cur) {
            while (oprStack.length > 0) {
                const out = oprStack.pop()
                if ("(" === out) break
                varStack.push(out)
            }
        } else if (OPERATOR_REG.test(cur)) {
            //如果此时栈oprStack为空，则直接将运算符加入到栈varStack中
            if (oprStack.length == 0) {
                oprStack.push(cur)
            }
            //如果此时栈oprStack不为空
            else {
                const top = oprStack[oprStack.length - 1]
                //当前遍历的运算符的优先级大于等于栈顶运算符的优先级,直接入oprStack栈
                if (compareOpr(cur, top)) {
                    oprStack.push(cur)
                }
                //当前遍历的运算符的优先级小于oprStack栈顶运算符的优先级，则将oprStack栈顶运算符一直出栈加入到栈varStack中，直到oprStack栈为空或者遇到一个运算符的优先级小于等于cur的优先级，此时将cur加入到栈varStack中
                else {
                    while (oprStack.length > 0) {
                        const out = oprStack.pop()
                        if (compareOpr(cur, out)) break;
                        varStack.push(out)
                    }
                    oprStack.push(cur)
                }
            }
        } else {
        }
        // console.log(varStack, oprStack)
    }
    while (oprStack.length > 0) {
        varStack.push(oprStack.pop())
    }
    return varStack
}

/**
 * 比较运算符的优先级
 * @param opr1
 * @param opr2
 * @returns {boolean}
 */
function compareOpr(opr1, opr2) {
    return descOpr[opr1] > descOpr[opr2]
}

/**
 * 计算前缀表达式
 * @param prefixExpression 数组 []
 */
function calcPrefixExpression(prefixExpression) {
    let stack = []
    while (prefixExpression.length > 0) {
        const cur = prefixExpression.shift()
        if (OP_REG.test(cur)) stack.push(cur)
        else if (OPERATOR_REG.test(cur)) {
            const r = new Number(stack.pop())
            const l = new Number(stack.pop())

            let res;
            switch (cur) {
                case "+":
                    res = l + r;
                    break;
                case "-":
                    res = l - r;
                    break;
                case "*":
                    res = l * r;
                    break;
                case "/":
                    res = l / r;
                    break;
            }
            // console.log(l+cur+r)
            stack.push(res)
        }
        // console.log(stack,prefixExpression)
    }
    return stack
}

/**
 * 校验表达式格式是否正确
 * @param expre
 */
function parseExpre(expre) {
    const expreCharArray = expre.split(/(\+|\-|\*|\/|\>=|\<=|\==|\!=|\>|\<|\(|\))+/)
    // console.log(expreCharArray)
    let supOprs = ["+", "-", "*", "/", ">", ">=", "<", "<=", "==", "!=", "(", ")"]
    let oprs = []
    let lets = []
    expreCharArray.forEach(char => {
        if (supOprs.indexOf(char) > -1) {
            oprs.unshift(char)
        } else {
            lets.unshift(char)
        }
    })
    // console.log(oprs)
    // console.log(lets)
}

/**
 * 计算中缀表达式
 * @param midExpression
 */
function calcMidExpression(midExpression) {
    let prefixExpression = getPrefixExpression(midExpression);
    // console.log(prefixExpression)
    let res = calcPrefixExpression(prefixExpression)
    // console.log(res)
    return res[0];
}

/**
 * 格式化中缀表达式  如：A+(B-C))*D => (A+(B-C))*D
 * @param midExpression
 */
function formatMidExpression(midExpression) {
    let prefixExpression = getPrefixExpression(midExpression)
    console.log(prefixExpression)
    const VAR_REG = /^[A-Z]$/
    let stack = []
    let res = true
    while (prefixExpression.length > 0) {
        const cur = prefixExpression.shift()
        if (VAR_REG.test(cur)) stack.push(cur)
        else if (OPERATOR_REG.test(cur)) {
            let r = stack.pop();
            let l = stack.pop();
            if (!r || !l) {
                res = false
                break
            }
            // console.log(l,cur,r)
            stack.push(`(${l}${cur}${r})`)
            /*stack.push('(')
            stack.push(l)
            stack.push(cur)
            stack.push(r)
            stack.push(')')*/
        }
    }
    if (!res) return ""
    return stack
}

function getValidatePrefixExpression(midExpre) {
    let varStack = []
    let oprStack = []
    // (1+(3*4)/6)-5
    for (let i = 0; i < midExpre.length; i++) {
        console.log(varStack, oprStack)

        const cur = midExpre[i];
        if (OP_REG.test(cur)) {
            varStack.push(cur)
        } else if ("(" === cur) {
            oprStack.push(cur)
        } else if (")" === cur) {
            // oprStack.push(cur)
            let findLeft = false
            while (oprStack.length > 0) {
                const out = oprStack.pop()
                // console.log(out)
                if ("(" === out) {
                    findLeft = true;
                    break;
                }
                varStack.push(out)
            }
            if (!findLeft) oprStack.push(cur)
        } else if (OPERATOR_REG.test(cur)) {
            //如果此时栈oprStack为空，则直接将运算符加入到栈varStack中
            if (oprStack.length == 0) {
                oprStack.push(cur)
            }
            //如果此时栈oprStack不为空
            else {
                const top = oprStack[oprStack.length - 1]
                //当前遍历的运算符的优先级大于等于栈顶运算符的优先级,直接入oprStack栈
                if (compareOpr(cur, top)) {
                    oprStack.push(cur)
                }
                //当前遍历的运算符的优先级小于oprStack栈顶运算符的优先级，则将oprStack栈顶运算符一直出栈加入到栈varStack中，直到oprStack栈为空或者遇到一个运算符的优先级小于等于cur的优先级，此时将cur加入到栈varStack中
                else {
                    while (oprStack.length > 0) {
                        const out = oprStack.pop()
                        if (compareOpr(cur, out)) break;
                        varStack.push(out)
                    }
                    oprStack.push(cur)
                }
            }
        } else {
        }
    }
    while (oprStack.length > 0) {
        varStack.push(oprStack.pop())
    }
    return varStack

}
/**
 * 校验不等式 格式是否正确
 * @param midExpression
 * @returns {boolean}
 */
function isValidInequationFormat(midExpression){
    let expression = midExpression.split(/>=|==|<=|!=|>|</)
    console.log(expression)
    if (expression.length!=2) return false
    let lRes = isValidExpressionFormat(expression[0])
    let rRes = isValidExpressionFormat(expression[1])
    console.log(lRes,rRes)
    return lRes&&rRes
}

/**
 * 校验表达式格式是否正确
 * @param midExpression
 * @returns {boolean}
 */
function isValidExpressionFormat(midExpression) {

    let varStack = []
    let oprStack = []
    let leftBracketStack = []
    let rightBracketStack = []

    const OPR_REG = /^\+|\-|\*|\/$/
    const VAR_REG = /^\w+$/

    for (let i=0;i<midExpression.length;i++){
        let cur = midExpression[i]
        if (OPR_REG.test(cur)) oprStack.push(cur)
        else if(VAR_REG.test(cur)){
            varStack.push(cur)
        }
        else if("("==cur){
            leftBracketStack.push(cur)
        }
        else if(")"==cur){
            rightBracketStack.push(cur)
        }
    }
    console.log(varStack,oprStack,leftBracketStack,rightBracketStack)

    //校验括号是否匹配
    if (leftBracketStack.length!=rightBracketStack.length) return false

    let res = true
    while (varStack.length>0){
        const curOpr = oprStack.pop()
        if (!curOpr) {break;}


        let r = varStack.pop()
        let l = varStack.pop()
        console.log(l,curOpr,r)
        if ( !r || !l ) {
            res = false;break;
        }
        if (!VAR_REG.test(r) ) {res = false;break;}
        if (!VAR_REG.test(l) ) {res = false;break;}
        varStack.push(l)
    }
    console.log(varStack,oprStack)
    if (!oprStack.length==0 || !varStack.length==1) res = false
    return res
}

export default {
    // calcMidExpression,
    // formatMidExpression,
    isValidInequationFormat,
    isValidExpressionFormat,
    // getPrefixExpression,
}